--[[
DlgBase:
对话框的基础定义，基类
--]]

G_NextDlgID = 100;

-- class: DlgBase
DlgBase = DefineClass(
{
    _DlgType = "DlgBase";-- 对话类型
    _ID = 0;-- 唯一id
    _Window = nil;-- 对话框对应的窗口
    _Closed = false;-- 是否关闭
    _Timered = false;-- 是否注册过时间回调器
    _UIModeled = false;
    _FrequentlyUpdater = nil;-- 注册的调频更新
    _MaxHideTime = 600;-- 单位秒
    _LastHideTime = 0;-- 上次隐藏时间
    _Hidden = false;-- 是否隐藏
    _Tweeners = Vector.Nil;-- 所有的tween

    _ParentDlg = nil;-- 父Dlg
    _ChildrenDlgVec = nil;-- 子Dlg Vector
} );

function DlgBase:DeriveClass(sub)
    return DeriveClass(DlgBase, sub);
end

function DlgBase:new()
    local dlg = New(self);
    dlg._ID = G_NextDlgID;
    G_NextDlgID = G_NextDlgID + 1;
    return dlg;
end

-- 初始化对话实例
-- args：不定参数
function DlgBase:Init(args)
    self._Window = self:PrepareInit();
    if self._Window == nil then
        LuaMidInterface.FatalError(self:GetDlgType() .. "'s PrepareInit creates Window failed!");
    end
    LuaMidInterface.windowMgr:AddWindow(self._Window, true);
    self._Window:Init();
    -- if self._Window.openSound and not self._Window.openSound.isZero then
    --     LuaMidInterface.audioMgr:PlayUISound(self._Window.openSound);
    -- end

    self:BeforeInit();
    self:OnInit(args);
    self:AfterInit();
    if self:IsVisible() then
        self:OnVisible(true);
    end
end

-- 初始化对话实例
-- args：不定参数
function DlgBase:InitAsSubDlg(parentWin, parentNode, args)
    self._Window = self:PrepareInit();
    if self._Window == nil then
        LuaMidInterface.FatalError(self:GetDlgType() .. "'s PrepareInit creates Window failed!");
    end
    LuaMidInterface.windowMgr:AddSubWindow(self._Window, parentWin, parentNode, true);
    self._Window:Init();
    if self._Window.openSound and not self._Window.openSound.isZero then
        LuaMidInterface.audioMgr:PlayUISound(self._Window.openSound);
    end

    self:BeforeInit();
    self:OnInit(args);
    self:AfterInit();
    if self:IsVisible() then
        self:OnVisible(true);
    end
end

-- return：关闭对话
function DlgBase:Close()
    if self._Closed then
        return;
    end
    self:SetVisible(false);
    if self._Window.closeSound and not self._Window.closeSound.isZero then
        LuaMidInterface.audioMgr:PlayUISound(self._Window.closeSound);
    end

    self:BeforeOnClose();
    self:OnClose();
    self:SetClickHitHandler(nil);
    self:RemoveFrequently();
    self:ClearAllTimers();
    self:KillAllTweeners();
    self:ClearAllUIModels();
    self._Closed = true;
    self:ClearAllEventListener();
end

-- 高级关闭：关闭包括当前窗口在内的整个窗口树
function DlgBase:SuperClose()
    if self._ParentDlg ~= nil then
        self._ParentDlg:SuperClose();
    else
        self:Close();
    end
end

-- 回收对话，外界不能随便调用
function DlgBase:Gabage()
    LuaMidInterface.windowMgr:DeleteWindow(self._Window);
    self._Window = nil;
end

-- return: 获取当前对话的实际类型
function DlgBase:GetDlgType()
    return self._DlgType;
end

-- return: 获取当前对话的id
function DlgBase:GetID()
    return self._ID;
end

-- return: 获取当前对话的根窗口
function DlgBase:GetWindow()
    return self._Window;
end

-- return: 获取当前对话的根容器(UYCtrlContainer)
function DlgBase:GetRoot()
    return self._Window.RootContainer;
end

-- return：对话是否有效（没有关闭）
function DlgBase:IsValid()
    return self._Closed == false;
end

-- return：对话是否已经关闭（不可再使用了）
function DlgBase:IsClosed()
    return self._Closed;
end

-- return: 对话是否可见
function DlgBase:IsVisible()
    return self._Closed == false and self._Window.Visible;
end

-- return: 隐藏的界面是否可以关闭
function DlgBase:CanClose()
    if self._Window and self._Window.Visible == false and self._Hidden then
        local hiddenTime = UYTimer.seconds - self._LastHideTime;
        if hiddenTime >= self._MaxHideTime then
            return true;
        end
    end
    return false;
end

-- 显示窗口并把窗口提到所在层级内部的最上层（注意这个函数不会让窗口改变层级）
function DlgBase:Show()
    self._Hidden = false;
    self:SetVisible(true);
end

-- 隐藏窗口
function DlgBase:Hide()
    self._Hidden = true;
    self:SetVisible(false);
    self._LastHideTime = UYTimer.seconds;
end

-- 把窗口提到所在层级内部的最上层（注意这个函数不会改变窗口层级）
function DlgBase:MoveToFront()
    LuaMidInterface.windowMgr:MoveWindowFront(self._Window);
end

-- 把串口提升到层级内部的最下层
function DlgBase:MoveToBottom()
    LuaMidInterface.windowMgr:MoveWindowBottom(self._Window);
end

-- 修改层级
-- layer 层级 WindowLayer
function DlgBase:ChangeLayer(layer)
    LuaMidInterface.windowMgr:ChangeWindowLayer(self._Window, layer);
    if self._ChildrenDlgVec == nil then
        return;
    end
    for i=1,self._ChildrenDlgVec:Size() do
        local dlg = self._ChildrenDlgVec:At(i);
        dlg._Window.Layer = layer;
    end
end

-- 获取当前窗口的层级
function DlgBase:GetWindowLayer()
    return self._Window.Layer;
end

-- 设置窗口可见性
-- visi: 是否可见
function DlgBase:SetVisible(visi)
    if self._Closed then
        return;
    end
    if self._Window.Visible ~= visi then
        self._Window.Visible = visi;
        if self._Window.Visible == visi then
            self:OnVisible(visi);
        end
    end
end

-- 设置关闭按钮是否可见
function DlgBase:SetCloseBtnVisible(v)
    self._Window.CloseButtonVisible = v;
end

-- 创建窗口的初始化
-- return: 一个Window句柄
function DlgBase:PrepareInit()
    return nil;
end

-- 窗口初始化完毕，OnInit调用之前的初始化处理
function DlgBase:BeforeInit()
end

-- 所有初始化完毕之后的处理
function DlgBase:AfterInit()
end

--- protected function for sub class to override--------------------------
-- 对话初始化完成后的处理，to override
-- args：初始化参数
function DlgBase:OnInit(args)
end

-- 每帧更新，to override
-- 注意，把这个函数注销是因为在DlgMgr里会判断它是否被子类重写了，重写了才会调用
-- function DlgBase:OnUpdate()
-- end

-- 对话关闭之前的处理，to override
function DlgBase:OnClose()
end

-- 对话隐藏|显示时的处理，to override
-- v: 是否可见
function DlgBase:OnVisible(v)
end

-- f7的处理（调试加速游戏功能使用）
-- return: 响应f7了返回true,否则返回false
function DlgBase:OnF7()
    return false;
end
-------------------------------------------------------------------------------

-- 获取子对象
function DlgBase:FetchGameObject(childName)
    return self:GetWindow():GetChild(childName);
end

-- 获取窗口文本控件
-- ctrlName: 控件名称
-- return: 指定名称的控件，保证不返回nil
function DlgBase:FetchLabel(ctrlName)
    return self:GetWindow():FetchLabel(ctrlName);
end

-- 获取窗口按钮控件
-- ctrlName: 控件名称
-- return: 指定名称的控件，保证不返回nil
function DlgBase:FetchButton(ctrlName)
    return self:GetWindow():FetchButton(ctrlName);
end

-- 获取窗口图片控件
-- ctrlName: 控件名称
-- return: 指定名称的控件，保证不返回nil
function DlgBase:FetchImage(ctrlName)
    return self:GetWindow():FetchImage(ctrlName);
end

-- 获取窗口面板（容器）控件
-- ctrlName: 控件名称
-- return: 指定名称的控件，保证不返回nil
function DlgBase:FetchPanel(ctrlName)
    return self:GetWindow():FetchPanel(ctrlName);
end

-- 获取窗口ScrollListLoop控件
-- ctrlName: 控件名称
-- return: 指定名称的控件。若不存在返回nil
function DlgBase:GetScrollListLoop(ctrlName)
    return self:GetWindow():GetScrollListLoop(ctrlName);
end

-- 获取窗口图片控件
-- ctrlName: 控件名称
-- return: 指定名称的控件，保证不返回nil
function DlgBase:GetRawImage(ctrlName)
    return self:GetWindow():GetRawImage(ctrlName);
end

-- 获取窗口YLabel控件
-- ctrlName: 控件名称
-- return: 指定名称的控件。保证不为nil
function DlgBase:GetGLabel(ctrlName)
    return self:GetWindow():GetGLabel(ctrlName);
end

-- 获取窗口YImage控件
-- ctrlName: 控件名称
-- return: 指定名称的控件。保证不为nil
function DlgBase:GetGImage(ctrlName)
    return self:GetWindow():GetGImage(ctrlName);
end

-- 获取inputfield空间
-- crtlName ：控件名称
-- return : 指定名称的控件。 保证不空
function DlgBase:GetGInputField(ctrlName)
    return self:GetWindow():GetGInputField(ctrlName);
end


-- 获取窗口YButton控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGButton(ctrlName)
    return self:GetWindow():GetGButton(ctrlName)
end

-- 获取窗口YToggle控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGToggle(ctrlName)
    return self:GetWindow():GetGToggle(ctrlName)
end


-- 获取窗口YObjList控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGObjList(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent("YObjList");
    end
end

-- 获取窗口YUIEffect控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGUIEffect(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent("YUIEffect");
    end
end

-- 获取窗口YInputFiled控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGInputField(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent("YInputField");
    end
end

-- 获取窗口YInputFiled控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGSpriteAnimation(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent("YSpriteAnimation");
    end
end

-- 获取窗口YRichLabel控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGRichLabel(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent(UI.YRichLabel);
    end
end

-- 获取窗口YTouchableGraphic控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGTouchableGraphic(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent(UI.YTouchableGraphic);
    end
end

-- 获取窗口YTouchableImage控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGTouchableImage(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent(UI.YTouchableImage);
    end
end

-- 获取窗口YTouchableLabel控件
-- ctrlName:控件名称
-- return :指定名称的控件
function DlgBase:GetGTouchableLabel(ctrlName)
    local obj = self:GetWindow():GetChild(ctrlName);
    if obj then
        return obj:GetComponent(UI.YTouchableLabel);
    end
end


-- 添加UYButton
-- pContainer 父容器
-- pTransform 父Transform
-- name 添加的GameObject名
-- pContainer与pTransform选填一项，以pContainer优先
function DlgBase:AddButton()
    return GuiUtil.CreateUYButton();
end

-- 添加UYImage
-- pContainer 父容器
-- pTransform 父Transform
-- name 添加的GameObject名
-- pContainer与pTransform选填一项，以pContainer优先
function DlgBase:AddImage()
    return GuiUtil.CreateYImage(self:GetWindowLayer());
end

-- 添加UYLabel
-- pContainer 父容器
-- pTransform 父Transform
-- name 添加的GameObject名
-- pContainer与pTransform选填一项，以pContainer优先
function DlgBase:AddLabel()
    return GuiUtil.CreateUYLabel();
end

-- 添加UYPanel
-- pContainer 父容器
-- pTransform 父Transform
-- name 添加的GameObject名
-- pContainer与pTransform选填一项，以pContainer优先
function DlgBase:AddPanel()
    return GuiUtil.CreateUYPanel();
end

-- 从根容器里创建一个UYImage控件
-- ctrlName: 控件名称，可以不填，会自动生成随机名称
-- return: UYImage控件
function DlgBase:CreateImage(ctrlName)
    return self:GetRoot():CreateImage(ctrlName);
end

-- 从根容器里创建一个UYLabel控件
-- ctrlName: 控件名称，可以不填，会自动生成随机名称
-- return: UYLabel控件
function DlgBase:CreateLabel(ctrlName)
    return self:GetRoot():CreateLabel(ctrlName);
end

-- 从根容器里创建一个UYButton控件
-- ctrlName: 控件名称，可以不填，会自动生成随机名称
-- return: UYButton控件
function DlgBase:CreateButton(ctrlName)
    return self:GetRoot():CreateButton(ctrlName);
end

-- 从根容器里创建一个UYPanel控件
-- ctrlName: 控件名称，可以不填，会自动生成随机名称
-- return: UYPanel控件
function DlgBase:CreatePanel(ctrlName)
    return self:GetRoot():CreatePanel(ctrlName);
end

--- protected function called by sub class--------------------------

-- 注册一个时间回调函数
-- func: 回调函数
-- frequency: 频率，秒为单位
-- repeats: 重复次数，-1表示无限重复（直到手工调用ClearTimer为止）
-- args: 回调函数参数，一个table，可以不填
-- return: Timer计时器句柄
function DlgBase:AddTimer(func, frequency, repeats, args)
    self._Timered = true;
    if repeats == nil then
        repeats = 1;
    end
    return UYLuaTimer.AddTimer(self, func, frequency, repeats, args);
end

-- 清理给定timer
-- return: nil
function DlgBase:ClearTimer(timer)
    return UYLuaTimer.ClearTimer(self, timer);
end

-- 清理当前Dlg注册的所有时间回调
function DlgBase:ClearAllTimers()
    if self._Timered == true then
        self._Timered = false;
        UYLuaTimer:ClearAllTimers(self);
    end
end

-- 注册一个tweener，在dlg关闭时会自动删除
-- tweener: 待注册的tweener
-- func: tweener完成时的回调，不想回调可以不传
-- args: 回调函数参数，可以不传
-- return：tweener本身
function DlgBase:KeepTweener(tweener, func, args)
    if tweener == nil then
        return nil;
    end
    if func ~= nil then
        if args == nil then
            tweener = DOTweenMgr.OnCompleteWithSelf(tweener, self, func);
        else
            tweener = DOTweenMgr.OnCompleteWithSelfAndArgs(tweener, self, func, args);
        end
    end
    if self._Tweeners == nil then
        self._Tweeners = Vector:new();
    end
    self._Tweeners:PushBack(tweener);
    return tweener;
end

-- 清理给定的tweener
-- tweener：待清理的tweener，可以传nil
-- return：nil （用于链式表达）
function DlgBase:KillTweener(tweener)
    if tweener == nil then
        return;
    end
    if self._Tweeners ~= nil then
        self._Tweeners:Remove(tweener);
    end
    DOTweenMgr.DestroyTween(tweener);
    return nil;
end

-- 清理所有tweeners
function DlgBase:KillAllTweeners()
    if self._Tweeners == nil then
        return;
    end
    for i = 1, self._Tweeners:Size() do
        DOTweenMgr.DestroyTween(self._Tweeners:At(i));
    end
    self._Tweeners:Clear();
end

-- 通过模型ID设置UIModel
function DlgBase:SetUIModelByModelID(rawImage, modelID, cameraSize)
    self._UIModeled = true;
    return LuaUIModelMgr.SetUIModelByModelID(self, rawImage, modelID, cameraSize);
end

-- 通过已有NPC设置UIModel
function DlgBase:SetUIModelByNpc(rawImage, npc, cameraSize)
    self._UIModeled = true;
    return LuaUIModelMgr.SetUIModelByNpc(self, rawImage, npc, cameraSize);
end

-- 通过NPCID设置UIModel
function DlgBase:SetUIModelByNpcID(rawImage, npcID, cameraSize)
    self._UIModeled = true;
    return LuaUIModelMgr.SetUIModelByNpcID(self, rawImage, npcID, cameraSize);
end

-- 通过NPCID设置UIModel
function DlgBase:SetUIModelByResID(rawImage, clothID, weaponID, cameraSize)
    self._UIModeled = true;
    return LuaUIModelMgr.SetUIModelByResID(self, rawImage, clothID, weaponID, cameraSize);
end

-- 删除指定UIModel
function DlgBase:ClearUIModel(uimodel)
    return LuaUIModelMgr.ClearUIModel(uimodel);
end

-- 清理所有UIModel
function DlgBase:ClearAllUIModels()
    if self._UIModeled then
        self._UIModeled = false;
        LuaUIModelMgr.ClearAllUIModels(self);
    end
end

function DlgBase:SetControlVisible(ctrl, v)
    if ctrl ~= nil then
        ctrl.gameObject:SetActive(v);
    end
end
function DlgBase:IsControlVisible(ctrl)
    if ctrl ~= nil then
        return ctrl.gameObject.activeSelf;
    end
    return false;
end

-- 返回 Dlg唯一ID
function DlgBase:ID()
    return self._ID;
end

-- Dlg 设置父Dlg
function DlgBase:SetParentDlg(parentDlg)
    self._ParentDlg = parentDlg;
end

-- 当子Dlg关闭时回调（清除子DlgVec对应数据）
function DlgBase:OnChildDlgClosed(childDlgId)
    if self._ChildrenDlgVec == nil then
        return;
    end
    local dlg = self:FindChildDlgById(childDlgId);
    if dlg ~= nil then
        self._ChildrenDlgVec:Remove(dlg);
    end
end

-- 添加子Dlg
-- parentTransform：父节点Transform, 可以指定任意transform
-- childDlgTable： 子Dlg luaTable
-- childargs： childargs 创建子Dlg参数
-- clearOtherChild： 是否删除其他子Dlg，独占
-- return： 创建好的子Dlg对象
function DlgBase:AddChildDlg(parentTransform, childDlgTable, childargs, clearOtherChild)
    if (parentTransform == nil or childDlgTable == nil) then
        return nil;
    end
--    local childDlg = DlgMgr:CreateSubDlg(self._Window, parentTransform.gameObject, childDlgTable, childargs);
    local childDlg = DlgMgr:CreateDlg(childDlgTable, childargs);
    if childDlg == nil then
        return nil;
    end
    childDlg:SetParentDlg(self);
    LuaMidInterface.windowMgr:AddSubWindow(childDlg:GetWindow(), self._Window, parentTransform.gameObject, true);
    local scale = Vector3(1, 1, 1);
    childDlg:GetWindow():GetComponent("RectTransform").localScale = scale;
    local pos = Vector3(0, 0, 0);
    childDlg:GetWindow():GetComponent(RectTransform).anchoredPosition3D = pos;
    if clearOtherChild ~= nil and clearOtherChild == true then
        self:ClearChildrenDlg();
    end

    if self._ChildrenDlgVec == nil then
        self._ChildrenDlgVec = Vector:new();
    end
    self._ChildrenDlgVec:PushBack(childDlg);
    return childDlg;
end

--- 设置Dlg位置
--- position Vector3 位置
function DlgBase:SetPosition(position)
    self:GetWindow():GetComponent(RectTransform).anchoredPosition3D = position;
end

-- 移除子Dlg
function DlgBase:RemoveChildDlg(childDlgTable)
    if self._ChildrenDlgVec == nil then
        return;
    end;

    local index = 0;
    while index < self._ChildrenDlgVec:Size() do
        index = index + 1;
        local dlg = self._ChildrenDlgVec:At(index);
        if dlg:GetDlgType() == childDlgTable._DlgType then
            dlg:SetParentDlg(nil);
            dlg:Close();
        end
    end
    self._ChildrenDlgVec:RemoveIf(FindObject("_DlgType", childDlgTable._DlgType));
end;

-- 判断是否有Dlg
function DlgBase:HasChildDlg(childDlgTable)
    if self._ChildrenDlgVec == nil then
        return false;
    end;
    local index = 0;
    while index < self._ChildrenDlgVec:Size() do
        index = index + 1;
        local dlg = self._ChildrenDlgVec:At(index);
        if dlg:GetDlgType() == childDlgTable._DlgType then
            return true
        end
    end
    return false;
end;

-- 根据Id在子对象Vector中查找子Dlg
function DlgBase:FindChildDlgById(id)
    if self._ChildrenDlgVec == nil then
        return nil;
    end;
    local index = 0;
    while index < self._ChildrenDlgVec:Size() do
        index = index + 1;
        local dlg = self._ChildrenDlgVec:At(index);
        if dlg:ID() == id then
            return dlg;
        end
    end
    return nil;
end

-- 清除所有子Dlg
function DlgBase:ClearChildrenDlg()
    if self._ChildrenDlgVec == nil then
        return;
    end;
    local index = 0;
    while index < self._ChildrenDlgVec:Size() do
        index = index + 1;
        local dlg = self._ChildrenDlgVec:At(index);
        dlg:SetParentDlg(nil);
        dlg:Close();
    end
    self._ChildrenDlgVec:Clear();
end

-- OnClose前调用的额外Close操作
function DlgBase:BeforeOnClose()
    if self._ParentDlg ~= nil then
        self._ParentDlg:OnChildDlgClosed(self._ID);
    end
    self:ClearChildrenDlg();
end

-- Dlg 中加入PopUpDlg 添加到ChildDlg中管理,具体参数看PopUpDlg
function DlgBase:PopUp(...)
    local popupDlg = PopUpDlg.ParentPopUp(self, ...);
    if popupDlg ~= nil then
        if self._ChildrenDlgVec == nil then
            self._ChildrenDlgVec = Vector:new();
        end
        self._ChildrenDlgVec:PushBack(popupDlg);
    end
end


-- 注册鼠标击中与否的处理回调函数
-- func: 回调函数，签名类似：
--         function(hitUIObj, hitMe)
--             hitUIObj: ui上被击中的GameObject，可能为null，说明没有对象被击中
--             hitMe: 是否击中当前窗口
function DlgBase:SetClickHitHandler(func)
    self:GetWindow():SetClickCheckHandler(self, func);
end

-- 注册高频刷新函数，一个Dlg对象只能有一个，以最后一个注册的为准
-- 回调函数
function DlgBase:AddFrequently(func)
    self:RemoveFrequently();
    if func ~= nil then
        self._FrequentlyUpdater = func;
        UYLuaTimer.AddFrequencyUpdate(self, self._FrequentlyUpdater);
    end
end

-- 删除高频刷新函数
function DlgBase:RemoveFrequently()
    if self._FrequentlyUpdater ~= nil then
        UYLuaTimer.RemoveFrequencyUpdate(self, self._FrequentlyUpdater);
        self._FrequentlyUpdater = nil;
    end
end

-- 判断是否注册过高频刷新
function DlgBase:HasFrequently()
    return self._FrequentlyUpdater ~= nil;
end

-- 添加事件监听
function DlgBase:AddEventListener(eventType, handler)
    AddEventListener(self, eventType, handler);
end

-- 是否已经监听事件
function DlgBase:HasEventListener(eventType)
    return HasEventListener(self, eventType);
end

-- 移除某个事件监听
function DlgBase:RemoveEventListener(eventType)
    RemoveEventListener(self, eventType)
end

-- 移除全部监听
function DlgBase:ClearAllEventListener()
    ClearAllEventListener(self);
end